package vip.liux.contracts.models.files;

import jakarta.annotation.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import vip.liux.contracts.repositories.files.DirectoryDescriptorRepository;
import vip.liux.contracts.repositories.files.FileDescriptorRepository;
import vip.liux.contracts.shared.kits.StorageKit;

import java.util.Optional;

@Component
public class FileManager {

    private static final Logger log = LoggerFactory.getLogger(FileManager.class);
    protected final FileDescriptorRepository fileDescriptorRepository;
    protected final DirectoryDescriptorRepository directoryDescriptorRepository;

    public FileManager(FileDescriptorRepository fileDescriptorRepository, DirectoryDescriptorRepository directoryDescriptorRepository) {
        this.fileDescriptorRepository = fileDescriptorRepository;
        this.directoryDescriptorRepository = directoryDescriptorRepository;
    }

    @Transactional
    public FileDescriptor create(String name, String mimeType, byte[] content, @Nullable Long directoryId, @Nullable String tenantId, @Nullable Boolean overrideExisting) {
        FileDescriptor fileDescriptor = saveFileDescriptor(name, mimeType, content.length, directoryId, tenantId, Optional.ofNullable(overrideExisting).orElse(false));

        // todo save content to storage
        StorageKit.save(fileDescriptor.getId().toString(), content);

        log.info("File {} has been created", name);
        return fileDescriptor;
    }

    protected FileDescriptor saveFileDescriptor(String name, String mimeType, int contentLength, @Nullable Long directoryId, @Nullable String tenantId, boolean overrideExisting) {
        FileDescriptor fileDescriptor = fileDescriptorRepository.findByName(name, directoryId);

        if (fileDescriptor != null) {
            if (!overrideExisting) {
                throw new FileAlreadyExistException(name);
            }

            fileDescriptor.setSize(contentLength);
            fileDescriptorRepository.save(fileDescriptor);
        } else {
            fileDescriptor = new FileDescriptor(
                    name, mimeType,
                    Optional.ofNullable(directoryId).flatMap(directoryDescriptorRepository::findById).orElse(null),
                    contentLength, tenantId);
            fileDescriptorRepository.save(fileDescriptor);
        }

        return fileDescriptor;
    }

    public void rename(FileDescriptor file, String newName) {
        FileDescriptor existingFile = fileDescriptorRepository.findByName(newName, file.getDirectoryId());

        if (existingFile != null) {
            throw new FileAlreadyExistException(newName);
        }
        file.setName(newName);
    }

    public void deleteAll(@Nullable Long directoryId) {
        for (FileDescriptor file : fileDescriptorRepository.getList(directoryId, null, Sort.unsorted())) {
            delete(file);
        }
    }

    public void delete(FileDescriptor file) {
        StorageKit.delete(file.getId().toString());
        // todo delete content from storage
        fileDescriptorRepository.delete(file);
    }

    public void move(FileDescriptor file, @Nullable Long newDirectoryId) {
        if (newDirectoryId != null) {
            Optional<DirectoryDescriptor> directoryDescriptor = directoryDescriptorRepository.findById(newDirectoryId);
            if (directoryDescriptor.isEmpty()) {
                throw new DirectoryNotExistException();
            }
            file.setDirectory(directoryDescriptor.get());
        } else {
            file.setDirectory(null);

        }
    }
}
